﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace JAAF.UI
{
    /// <summary>
    /// Implements a <see cref="ComponentModel.PropertyDescriptor"/> wrapper for a <see cref="JAAF.UI.StateElement"/>
    /// of a <see cref="JAAF.UI.UIProcess"/>.
    /// </summary>
    /// <remarks>
    /// <see cref="ComponentModel.PropertyDescriptor">Property descriptors</see> are used
    /// mainly to faciliate the data binding of properties to user interface controls.
    /// </remarks>
    public class StateElementPropertyDescriptor: PropertyDescriptor
    {
        /// <summary>
        /// The state element to wrap into a property descriptor
        /// </summary>
        private StateElement m_oElmnt;

        /// <summary>
        /// The UIProcess that owns the wrapped state element
        /// </summary>
        private UIProcess m_oOwningProcess;

        /// <summary>
        /// Initializes a new instance of the <see cref="StateElementPropertyDescriptor"/> class.
        /// </summary>
        /// <param name="_oOwningProcess">The owning process.</param>
        /// <param name="_oStateElement">The state element to wrap into a <see cref="ComponentModel.PropertyDescriptor"/>.</param>
        public StateElementPropertyDescriptor(UIProcess _oOwningProcess, StateElement _oStateElement)
            :base(_oStateElement.Name, null)
        {
            m_oOwningProcess = _oOwningProcess;
            m_oElmnt = _oStateElement;
        }

        /// <summary>
        /// Returns whether resetting an object changes its value.
        /// </summary>
        /// <param name="component">The component to test for reset capability.</param>
        /// <returns>
        /// Always false.
        /// </returns>
        public override bool CanResetValue(object component)
        {
            return false;
        }

        /// <summary>
        /// Gets the type of the component this property / state element is bound to.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.Type"/> that represents the type of component this property is bound to. 
        /// When the <see cref="M:System.ComponentModel.PropertyDescriptor.GetValue(System.Object)"/> 
        /// or <see cref="M:System.ComponentModel.PropertyDescriptor.SetValue(System.Object,System.Object)"/> 
        /// methods are invoked, the object specified might be an instance of this type.
        /// </returns>
        public override Type ComponentType
        {
            get { return m_oOwningProcess.GetType(); }
        }

        /// <summary>
        /// Gets the current value of the property / state element on a component.
        /// </summary>
        /// <param name="component">The component with the property for which to retrieve the value.</param>
        /// <returns>
        /// The value of a property for a given component.
        /// </returns>
        public override object GetValue(object component)
        {
            return m_oElmnt.Value;
        }

        /// <summary>
        /// Gets a value indicating whether this property / state element is read-only.
        /// </summary>
        /// <returns>true if the property is read-only; otherwise, false.</returns>
        public override bool IsReadOnly
        {
            get 
            {
                if ((m_oElmnt.AccessLevel & StateElementAccessLevelEnum.Write) == 0)
                    return true;
                else
                    return false;
            }
        }

        /// <summary>
        /// Gets the type of the property / state element.
        /// </summary>
        /// <returns>A <see cref="T:System.Type"/> that represents the type of the property.</returns>
        public override Type PropertyType
        {
            get 
            {
                if (m_oElmnt.Value != null)
                {
                    return m_oElmnt.Value.GetType();
                }
                else
                {
                    return null;
                }
            }
        }

        /// <summary>
        /// Resets the value for this property / state element the default value.
        /// </summary>
        /// <param name="component">The component  / UIProcess with the property value that is to be reset to the default value.</param>
        public override void ResetValue(object component)
        {
            m_oElmnt.Value = null;
        }

        /// <summary>
        /// Sets the value of the component to a different value.
        /// </summary>
        /// <param name="component">The component with the property value that is to be set.</param>
        /// <param name="value">The new value.</param>
        public override void SetValue(object component, object value)
        {
            object oOldValue = m_oElmnt.Value;
            m_oElmnt.Value = value;

            m_oOwningProcess.OnStateChangedTrigger(m_oElmnt.Name, oOldValue);
        }

        public override bool ShouldSerializeValue(object component)
        {
            return false;
        }
    }
}
